<template><div><h2 id="elasticsearch-extension-for-yii-2" tabindex="-1"><a class="header-anchor" href="#elasticsearch-extension-for-yii-2"><span>Elasticsearch Extension for Yii 2</span></a></h2>
<p>This extension provides the <a href="https://www.elastic.co/elasticsearch/" target="_blank" rel="noopener noreferrer">Elasticsearch</a> integration for the Yii2 framework. It includes basic querying/search support and also implements the <code v-pre>ActiveRecord</code> pattern that allows you to store active records in Elasticsearch.</p>
<h2 id="安装" tabindex="-1"><a class="header-anchor" href="#安装"><span>安装</span></a></h2>
<h3 id="requirements" tabindex="-1"><a class="header-anchor" href="#requirements"><span>Requirements</span></a></h3>
<p>The extension is designed to support Elasticsearch 5.0 and above. It has been tested with the latest versions of Elasticsearch 5.x, 6.x, and 7.x branches.</p>
<h3 id="configuring-elasticsearch" tabindex="-1"><a class="header-anchor" href="#configuring-elasticsearch"><span>Configuring Elasticsearch</span></a></h3>
<p>The extension uses inline scripts for some of its functionality (like the [[yii\elasticsearch\ActiveRecord::updateAllCounters()|updateAllCounters()]] method). The script is written in <code v-pre>painless</code>, which is run by Elasticsearch in a sanboxed manner. Because it is generally enabled by default, no special configuration is required. However, for older versions of Elasticsearch (like 5.0), you may need to enable inline scripts to support this functionality. See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-scripting-security.html" target="_blank" rel="noopener noreferrer">Elasticsearch documentation</a> for details.</p>
<h3 id="getting-composer-package" tabindex="-1"><a class="header-anchor" href="#getting-composer-package"><span>Getting Composer package</span></a></h3>
<p>The preferred way to install this extension is through <a href="http://getcomposer.org/download/" target="_blank" rel="noopener noreferrer">composer</a>:</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line"><span class="token function">composer</span> require yiisoft/yii2-elasticsearch</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h2 id="configuring-application" tabindex="-1"><a class="header-anchor" href="#configuring-application"><span>Configuring application</span></a></h2>
<p>To use this extension, you need to configure the [[yii\elasticsearch\Connection|Connection]] class in your application configuration:</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">return</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token comment">//....</span></span>
<span class="line">    <span class="token string single-quoted-string">'components'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'elasticsearch'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'yii\elasticsearch\Connection'</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token string single-quoted-string">'nodes'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">                <span class="token punctuation">[</span><span class="token string single-quoted-string">'http_address'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'127.0.0.1:9200'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token comment">// configure more hosts if you have a cluster</span></span>
<span class="line">            <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token comment">// set autodetectCluster to false if you don't want to auto detect nodes</span></span>
<span class="line">            <span class="token comment">// 'autodetectCluster' => false,</span></span>
<span class="line">            <span class="token string single-quoted-string">'dslVersion'</span> <span class="token operator">=></span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token comment">// default is 5</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>The connection needs to be configured with at least one node. The default behavior is cluster autodetection. The extension makes a <code v-pre>GET /_nodes</code> request to the first node in the list, and gets the addresses of all the nodes in the cluster. An active node is then randomly selected from the updated node list.</p>
<p>This behavior can be disabled by setting [[yii\elasticsearch\Connection::$autodetectCluster|$autodetectCluster]] to <code v-pre>false</code>. In that case an active node will be randomly selected from the nodes given in the configuration.</p>
<blockquote>
<p>For cluster autodetection to work properly, the <code v-pre>GET /_nodes</code> request to the nodes specified in the configuration must return the <code v-pre>http_address</code> field for each node. This is returned by vanilla Elasticsearch instances by default, but has been reported to not be available in environments like AWS. In that case you need to disable cluster detection and specify hosts manually.</p>
<p>It may also be useful to disable cluster autodetection for performance reasons. If a cluster has a single dedicated <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-node.html#coordinating-only-node" target="_blank" rel="noopener noreferrer">coordinating-only node</a>, it makes sense to direct all requests to that node. If a cluster contains only a few nodes and their addresses are known, it may be useful to specify them explicitly.</p>
</blockquote>
<p>You should set the version of the domain-specific language the extension will use to communicate with the server. The value corresponds to the version of the Elasticsearch server. For 5.x branch set [[yii\elasticsearch\Connection::$dslVersion|$dslVersion]] to <code v-pre>5</code>, for 6.x branch to <code v-pre>6</code>, for 7.x branch to <code v-pre>7</code>. Default is <code v-pre>5</code>.</p>
<h2 id="mapping-indexing" tabindex="-1"><a class="header-anchor" href="#mapping-indexing"><span>Mapping &amp; Indexing</span></a></h2>
<h3 id="comparison-with-sql" tabindex="-1"><a class="header-anchor" href="#comparison-with-sql"><span>Comparison with SQL</span></a></h3>
<p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/_mapping_concepts_across_sql_and_elasticsearch.html" target="_blank" rel="noopener noreferrer">Elasticsearch documentation</a> provides an extensive list of concepts in Elasticsearch and SQL and how they map to one another. We’ll focus on the basics.</p>
<p>An Elasticsearch cluster consists of one or more Elasticsearch instances. Requests are sent to one of the instances, which propagates the query to other instances in the cluster, collects results, and then returns them to the client. Therefore a cluster or an instance that represents it roughly correspond to a SQL database.</p>
<p>In Elasticsearch data is stored in indices. An index corresponds to a SQL table.</p>
<p>An index contains documents. Documents correspond to rows in a SQL table. In this extension, an [[yii\elasticsearch\ActiveRecord|ActiveRecord]] represents a document in an index. The operation of saving a document into an index is called indexing.</p>
<p>The schema or structure of a document is defined in the so-called mapping. A mapping defines document fields, which correspond to columns in SQL. In Elasticsearch the primary key field is special, because it always exists and its name and structure can not be changed. Other fields are fully configurable.</p>
<h3 id="mapping-fields-beforehand" tabindex="-1"><a class="header-anchor" href="#mapping-fields-beforehand"><span>Mapping fields beforehand</span></a></h3>
<p>Even though new fields will be created on the fly when documents are indexed, it is considered good practice to define a mapping before indexing documents.</p>
<p>Generally, once an attribute is defined, it is not possible to change its type. For example if a text field is configured to use the English language analyzer, it is not possible to switch to a different language without reindexing every document in the index. Certain limited modifications to mapping can be applied on the fly. See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-put-mapping.html#updating-field-mappings" target="_blank" rel="noopener noreferrer">Elasticsearch documentation</a> for more info.</p>
<h3 id="document-types" tabindex="-1"><a class="header-anchor" href="#document-types"><span>Document types</span></a></h3>
<p>Originally, Elasticsearch was designed to store documents with different structure in the same index. To handle this, a concept of “type” was introduced. However, this approach soon fell out of favor. As a result, types have been <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/removal-of-types.html" target="_blank" rel="noopener noreferrer">removed from Elasticsearch 7.x</a>.</p>
<p>Currently, best practice is to have only one type per index. Technically, if the extension is configured for Elasticsearch 7 or above, [[yii\elasticsearch\ActiveRecord::type()|type()]] is ignored, and implicitly replaced with <code v-pre>_doc</code> where required by the API.</p>
<h3 id="creating-helper-methods" tabindex="-1"><a class="header-anchor" href="#creating-helper-methods"><span>Creating helper methods</span></a></h3>
<p>Our recommendation is to create several static methods in your [[yii\elasticsearch\ActiveRecord|ActiveRecord]] model that deal with index creation and updates. Here is one example of how this can be done.</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">Customer</span> <span class="token keyword">extends</span> <span class="token class-name class-name-fully-qualified">yii<span class="token punctuation">\</span>elasticsearch<span class="token punctuation">\</span>ActiveRecord</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// Other class attributes and methods go here</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * <span class="token keyword">@return</span> <span class="token class-name"><span class="token keyword">array</span></span> This model's mapping</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">function</span> <span class="token function-definition function">mapping</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token comment">// Field types: https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html#field-datatypes</span></span>
<span class="line">            <span class="token string single-quoted-string">'properties'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">                <span class="token string single-quoted-string">'first_name'</span>     <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'type'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'text'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token string single-quoted-string">'last_name'</span>      <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'type'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'text'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token string single-quoted-string">'order_ids'</span>      <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'type'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'keyword'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token string single-quoted-string">'email'</span>          <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'type'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'keyword'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token string single-quoted-string">'registered_at'</span>  <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'type'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'date'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token string single-quoted-string">'updated_at'</span>     <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'type'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'date'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token string single-quoted-string">'status'</span>         <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'type'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'keyword'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token string single-quoted-string">'is_active'</span>      <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'type'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'boolean'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token punctuation">]</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * Set (update) mappings for this model</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">function</span> <span class="token function-definition function">updateMapping</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token variable">$db</span> <span class="token operator">=</span> <span class="token keyword static-context">static</span><span class="token operator">::</span><span class="token function">getDb</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$command</span> <span class="token operator">=</span> <span class="token variable">$db</span><span class="token operator">-></span><span class="token function">createCommand</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$command</span><span class="token operator">-></span><span class="token function">setMapping</span><span class="token punctuation">(</span><span class="token keyword static-context">static</span><span class="token operator">::</span><span class="token function">index</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword static-context">static</span><span class="token operator">::</span><span class="token function">type</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword static-context">static</span><span class="token operator">::</span><span class="token function">mapping</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * Create this model's index</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">function</span> <span class="token function-definition function">createIndex</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token variable">$db</span> <span class="token operator">=</span> <span class="token keyword static-context">static</span><span class="token operator">::</span><span class="token function">getDb</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$command</span> <span class="token operator">=</span> <span class="token variable">$db</span><span class="token operator">-></span><span class="token function">createCommand</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$command</span><span class="token operator">-></span><span class="token function">createIndex</span><span class="token punctuation">(</span><span class="token keyword static-context">static</span><span class="token operator">::</span><span class="token function">index</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token comment">//'aliases' => [ /* ... */ ],</span></span>
<span class="line">            <span class="token string single-quoted-string">'mappings'</span> <span class="token operator">=></span> <span class="token keyword static-context">static</span><span class="token operator">::</span><span class="token function">mapping</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token comment">//'settings' => [ /* ... */ ],</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * Delete this model's index</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">function</span> <span class="token function-definition function">deleteIndex</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token variable">$db</span> <span class="token operator">=</span> <span class="token keyword static-context">static</span><span class="token operator">::</span><span class="token function">getDb</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$command</span> <span class="token operator">=</span> <span class="token variable">$db</span><span class="token operator">-></span><span class="token function">createCommand</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$command</span><span class="token operator">-></span><span class="token function">deleteIndex</span><span class="token punctuation">(</span><span class="token keyword static-context">static</span><span class="token operator">::</span><span class="token function">index</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword static-context">static</span><span class="token operator">::</span><span class="token function">type</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>To create the index with proper mappings, call <code v-pre>Customer::createIndex()</code>. If you have changed the mapping in a way that allows mapping update (e.g. created a new property), call <code v-pre>Customer::updateMapping()</code>.</p>
<p>However, if you have changed a property (e.g. went from <code v-pre>string</code> to <code v-pre>date</code>), Elasticsearch will not be able to update the mapping. In this case you need to delete your index (by calling <code v-pre>Customer::deleteIndex()</code>), create it anew with updated mapping (by calling <code v-pre>Customer::createIndex()</code>), and then repopulate it with data.</p>
<h2 id="using-the-query" tabindex="-1"><a class="header-anchor" href="#using-the-query"><span>Using the Query</span></a></h2>
<p>The [[yii\elasticsearch\Query]] class is generally compatible with its [[yii\db\Query|parent query class]], well-described in the <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide/db-query-builder.md" target="_blank" rel="noopener noreferrer">guide</a>.</p>
<p>The differences are outlined below.</p>
<ul>
<li>
<p>As Elasticsearch does not support SQL, the query API does not support <code v-pre>join()</code>, <code v-pre>groupBy()</code>, <code v-pre>having()</code>, and <code v-pre>union()</code>. Sorting, <code v-pre>limit()</code>, <code v-pre>offset()</code>, <code v-pre>limit()</code>, and <code v-pre>where()</code> are all supported (with certain limitations).</p>
</li>
<li>
<p>[[yii\elasticsearch\Query::from()|from()]] does not select the tables, but the <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/glossary.html#glossary-index" target="_blank" rel="noopener noreferrer">index</a> and <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/glossary.html#glossary-type" target="_blank" rel="noopener noreferrer">type</a> to query against.</p>
</li>
<li>
<p><code v-pre>select()</code> has been replaced with [[yii\elasticsearch\Query::storedFields()|storedFields()]]. It defines the fields to retrieve from a document, similar to columns in SQL.</p>
</li>
<li>
<p>As Elasticsearch is not only a database but also a search engine, additional query and aggregation mechanisms are supported. Check out the <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html" target="_blank" rel="noopener noreferrer">Query DSL</a> on how to compose queries.</p>
</li>
</ul>
<h3 id="executing-queries" tabindex="-1"><a class="header-anchor" href="#executing-queries"><span>Executing queries</span></a></h3>
<p>The [[yii\elasticsearch\Query]] class provides the usual methods for executing queries: [[yii\elasticsearch\Query::one()|one()]] and [[yii\elasticsearch\Query::all()|all()]]. They return only the search results (or a single result).</p>
<p>There is also the [[yii\elasticsearch\Query::search()|search()]] method that returns both the search results, and all of the metadata retrieved from Elasticsearch, including aggregations.</p>
<p>The extension fully supports the highly efficient scroll mode, that allows to retrieve large results sets. See [[yii\elasticsearch\Query::batch()|batch()]] and [[yii\elasticsearch\Query::each()|each()]] for more information.</p>
<h3 id="number-of-returned-records-and-pagination-caveats" tabindex="-1"><a class="header-anchor" href="#number-of-returned-records-and-pagination-caveats"><span>Number of returned records and pagination caveats</span></a></h3>
<p>Unlike most SQL servers that will return all results unless a <code v-pre>LIMIT</code> clause is provided, Elasticsearch limits the result set to 10 records by default. To get more records, use [[yii\elasticsearch\Query::limit()|limit()]]. This is especially important when defining relations in [[yii\elasticsearch\ActiveRecord|ActiveRecord]], where record limit needs to be specified explicitly.</p>
<p>Elasticsearch is generally poor suited to tasks that require deep pagination. It is optimized for search engine behavior, where only first few pages of results have any relevance. While it is technically possible to go far into the result set using [[yii\elasticsearch\Query::limit()|limit()]] and [[yii\elasticsearch\Query::offset()|offset()]], performance is reduced.</p>
<p>One possible solution would be to use the scroll mode, which behaves similar to cursors in traditional SQL databases. Scroll mode is implemented with [[yii\elasticsearch\Query::batch()|batch()]] and [[yii\elasticsearch\Query::each()|each()]] methods.</p>
<h3 id="error-handling-in-queries" tabindex="-1"><a class="header-anchor" href="#error-handling-in-queries"><span>Error handling in queries</span></a></h3>
<p>Elasticsearch is a distributed database. Because of its distributed nature, certain requests may be partially successful.</p>
<p>Consider how a typical search is performed. The query is sent to all relevant shards, then their results are collected, processed, and returned to user. It is possible that not all shards are able to return a result. Yet, even with some data missing, the result may be useful.</p>
<p>With every query the server returns <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html#search-api-response-body" target="_blank" rel="noopener noreferrer">some additional metadata</a>, including data on which shards failed. This data is lost when using standard Yii2 methods like [[yii\elasticsearch\Query::one()|one()]] and [[yii\elasticsearch\Query::all()|all()]]. Even if some shards failed, it is not considered a server error.</p>
<p>To get extended data, including shard statictics, use the [[yii\elasticsearch\Query::search()|search()]] method.</p>
<p>The query itself can also fail for a number of reasons (connectivity issues, syntax error, etc.) but that will result in an exception.</p>
<h3 id="error-handling-in-bulk-requests" tabindex="-1"><a class="header-anchor" href="#error-handling-in-bulk-requests"><span>Error handling in bulk requests</span></a></h3>
<p>In Elasticsearch a <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html" target="_blank" rel="noopener noreferrer">bulk request</a> performs multiple operations in a single API call. This reduces overhead and can greatly increase indexing speed.</p>
<p>The operations are executed individually, so some can be successful, while others fail. Having some of the operations fail does not cause the whole bulk request to fail. If it is important to know if any of the constituent operations failed, the [[yii\elasticsearch\BulkCommand::execute()|result of the bulk request]] needs to be checked.</p>
<p>The bulk request itself can also fail, for example, because of connectivity issues, but that will result in an exception.</p>
<h3 id="document-counts-in-es-7-0-0" tabindex="-1"><a class="header-anchor" href="#document-counts-in-es-7-0-0"><span>Document counts in ES &gt; 7.0.0</span></a></h3>
<p>As of Elasticsearch 7.0.0, for result sets over 10 000 hits, document counts (<code v-pre>total_hits</code>) are <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/breaking-changes-7.0.html#track-total-hits-10000-default" target="_blank" rel="noopener noreferrer">no longer exact by default</a>. In other words, if the result set contains more than 10 000 documents, <code v-pre>total_hits</code> is reported as 10 000, and if it is less, then it is reported exactly. This results in a performance improvement.</p>
<p>The <code v-pre>track_total_hits</code> option can be used to change this behavior. If it is set to <code v-pre>'true'</code>, exact document count will always be returned, and an integer value overrides the default threshold value of 10 000.</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$query</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$query</span><span class="token operator">-></span><span class="token function">from</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'customer'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// Note the literal string 'true', not a boolean value!</span></span>
<span class="line"><span class="token variable">$query</span><span class="token operator">-></span><span class="token function">addOptions</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'track_total_hits'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'true'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="runtime-fields-mappings-in-es-7-11" tabindex="-1"><a class="header-anchor" href="#runtime-fields-mappings-in-es-7-11"><span>Runtime Fields/Mappings in ES &gt;= 7.11</span></a></h3>
<p>Runtime Fields are fields that can be dynamically generated at query time by supplying a script similar to <code v-pre>script_fields</code>. The major difference being that the value of a Runtime Field can be used in search queries, aggregations, filtering, and sorting.</p>
<p>Any Runtime Field values that you want to be included in the search results must be added to the <code v-pre>field</code> array by passing an array of field names using the <code v-pre>fields()</code> method.</p>
<p>Example for fetching users’ full names by concatenating the <code v-pre>first_name</code> and <code v-pre>last_name</code> fields from the index and sorting them alphabetically.</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$results</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name class-name-fully-qualified">yii<span class="token punctuation">\</span>elasticsearch<span class="token punctuation">\</span>Query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token operator">-></span><span class="token function">from</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'users'</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token operator">-></span><span class="token function">runtimeMappings</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'full_name'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token string single-quoted-string">'type'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'keyword'</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token string single-quoted-string">'script'</span> <span class="token operator">=></span> <span class="token string double-quoted-string">"emit(doc['first_name'].value + ' ' + doc['last_name'].value)"</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token operator">-></span><span class="token function">fields</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'full_name'</span><span class="token punctuation">]</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token operator">-></span><span class="token function">orderBy</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'full_name'</span> <span class="token operator">=></span> <span class="token constant">SORT_ASC</span><span class="token punctuation">]</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token operator">-></span><span class="token function">search</span><span class="token punctuation">(</span><span class="token variable">$connection</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>For more information concerning <code v-pre>type</code> and <code v-pre>script</code> please see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/runtime.html" target="_blank" rel="noopener noreferrer">Elastic’s Runtime Field Documentation</a></p>
<h2 id="using-the-activerecord" tabindex="-1"><a class="header-anchor" href="#using-the-activerecord"><span>Using the ActiveRecord</span></a></h2>
<p>Elasticsearch ActiveRecord is very similar to the database ActiveRecord as described in the <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide/active-record.md" target="_blank" rel="noopener noreferrer">guide</a>.</p>
<p>Most of its limitations and differences are derived from the [[yii\elasticsearch\Query]] implementation.</p>
<p>For defining an Elasticsearch ActiveRecord class your record class needs to extend from [[yii\elasticsearch\ActiveRecord]] and implement at least the [[yii\elasticsearch\ActiveRecord::attributes()|attributes()]] method to define the attributes of the record.</p>
<blockquote>
<p>NOTE: It is important NOT to include the primary key attribute (<code v-pre>_id</code>) in the attributes.</p>
</blockquote>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">Customer</span> <span class="token keyword">extends</span> <span class="token class-name class-name-fully-qualified">yii<span class="token punctuation">\</span>elasticsearch<span class="token punctuation">\</span>ActiveRecord</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// Other class attributes and methods go here</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">attributes</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'first_name'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'last_name'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'order_ids'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'email'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'registered_at'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'updated_at'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'status'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'is_active'</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>You may override [[yii\elasticsearch\ActiveRecord::index()|index()]] and [[yii\elasticsearch\ActiveRecord::type()|type()]] to define the index and type this record represents.</p>
<blockquote>
<p>NOTE: Type is ignored for Elasticsearch 7.x and above. See <a href="https://github.com/yiisoft/yii2-elasticsearch/blob/master/docs/guide/mapping-indexing.md" target="_blank" rel="noopener noreferrer">Data Mapping &amp; Indexing</a> for more information.</p>
</blockquote>
<h3 id="usage-examples" tabindex="-1"><a class="header-anchor" href="#usage-examples"><span>Usage examples</span></a></h3>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token comment">// Creating a new record</span></span>
<span class="line"><span class="token variable">$customer</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Customer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$customer</span><span class="token operator">-></span><span class="token property">_id</span> <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token comment">// setting primary keys is only allowed for new records</span></span>
<span class="line"><span class="token variable">$customer</span><span class="token operator">-></span><span class="token property">last_name</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'Doe'</span><span class="token punctuation">;</span> <span class="token comment">// attributes can be set one by one</span></span>
<span class="line"><span class="token variable">$customer</span><span class="token operator">-></span><span class="token property">attributes</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'first_name'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'Jane'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'email'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'janedoe@example.com'</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">// or together</span></span>
<span class="line"><span class="token variable">$customer</span><span class="token operator">-></span><span class="token function">save</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// Getting records using the primary key</span></span>
<span class="line"><span class="token variable">$customer</span> <span class="token operator">=</span> <span class="token class-name static-context">Customer</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// get a record by pk</span></span>
<span class="line"><span class="token variable">$customer</span> <span class="token operator">=</span> <span class="token class-name static-context">Customer</span><span class="token operator">::</span><span class="token function">findOne</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// also works</span></span>
<span class="line"><span class="token variable">$customers</span> <span class="token operator">=</span> <span class="token class-name static-context">Customer</span><span class="token operator">::</span><span class="token function">mget</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// get multiple records by pk</span></span>
<span class="line"><span class="token variable">$customers</span> <span class="token operator">=</span> <span class="token class-name static-context">Customer</span><span class="token operator">::</span><span class="token function">findAll</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// also works</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// Finding records using simple conditions</span></span>
<span class="line"><span class="token variable">$customer</span> <span class="token operator">=</span> <span class="token class-name static-context">Customer</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">where</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'first_name'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'John'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'last_name'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'Smith'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">one</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// Finding records using query DSL</span></span>
<span class="line"><span class="token comment">// (see https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query.html)</span></span>
<span class="line"><span class="token variable">$articles</span> <span class="token operator">=</span> <span class="token class-name static-context">Article</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'match'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'title'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'yii'</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">all</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$articles</span> <span class="token operator">=</span> <span class="token class-name static-context">Article</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'bool'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'must'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token punctuation">[</span><span class="token string single-quoted-string">'term'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'is_active'</span> <span class="token operator">=></span> <span class="token constant boolean">true</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token punctuation">[</span><span class="token string single-quoted-string">'terms'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'email'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'johnsmith@example.com'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'janedoe@example.com'</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">]</span></span>
<span class="line">        <span class="token punctuation">]</span></span>
<span class="line">    <span class="token punctuation">]</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">all</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="primary-keys" tabindex="-1"><a class="header-anchor" href="#primary-keys"><span>Primary keys</span></a></h3>
<p>Unlike traditional SQL databases that let you define a primary key as any column or a set of columns, or even create a table without a primary key, Elasticsearch stores the primary key separately from the rest of the document. The key is not the part of the document structure and can not be changed once the document is saved into the index.</p>
<p>While Elasticsearch can create unique primary keys for new documents, it is also possible to specify them explicitly for new records. Note that the key attribute is a string and is limited to 512 bytes. See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-id-field.html" target="_blank" rel="noopener noreferrer">Elasticsearch docs</a> for more information.</p>
<p>In Elasticsearch, the name of the primary key is <code v-pre>_id</code>, and [[yii\elasticsearch\ActiveRecord]] provides getter and setter methods to access it as a property. There is no need to add it to [[yii\elasticsearch\ActiveRecord::attributes()|attributes()]].</p>
<h3 id="foreign-keys" tabindex="-1"><a class="header-anchor" href="#foreign-keys"><span>Foreign keys</span></a></h3>
<p>SQL databases often use autoincremented integer columns as primary keys. When models from such databases are used in relations in Elasticsearch models, those integers effectively become foreign keys.</p>
<p>Even though these keys are technically numeric, generally they should not be mapped as a numeric field datatype. Elasticsearch optimizes numeric fields, such as integer or long, for range queries. However, keyword fields are better for term and other term-level queries. Therefore it is recommended to use <code v-pre>keyword</code> field type for foreign keys. See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/keyword.html" target="_blank" rel="noopener noreferrer">Elasticsearch docs</a> for more information on keyword fields.</p>
<h3 id="defining-relations" tabindex="-1"><a class="header-anchor" href="#defining-relations"><span>Defining relations</span></a></h3>
<p>It is possible to define relations from Elasticsearch ActiveRecords to other Elasticsearch and non-Elasticsearch ActiveRecord classes and vice versa. However, [[yii\elasticsearch\ActiveQuery::via()|Via]]-relations can not be defined using a table as there are no tables in Elasticsearch. You can only define such relations using other relations.</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">Customer</span> <span class="token keyword">extends</span> <span class="token class-name class-name-fully-qualified">yii<span class="token punctuation">\</span>elasticsearch<span class="token punctuation">\</span>ActiveRecord</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// Every customer has multiple orders, every order has exactly one invoice</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">getOrders</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token comment">// This relation gets up to 100 most recent orders of current customer</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">hasMany</span><span class="token punctuation">(</span><span class="token class-name static-context">Order</span><span class="token operator">::</span><span class="token function">className</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'customer_id'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'_id'</span><span class="token punctuation">]</span><span class="token punctuation">)</span></span>
<span class="line">                    <span class="token operator">-></span><span class="token function">orderBy</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'created_at'</span> <span class="token operator">=></span> <span class="token constant">SORT_DESC</span><span class="token punctuation">]</span><span class="token punctuation">)</span></span>
<span class="line">                    <span class="token operator">-></span><span class="token function">limit</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// override the default limit of 10</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">getInvoices</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token comment">// This via-relation works by fetching the related "orders"</span></span>
<span class="line">        <span class="token comment">// models first. This query also needs a limit, but it makes</span></span>
<span class="line">        <span class="token comment">// no sense to make that limit different from the underlying</span></span>
<span class="line">        <span class="token comment">// relation.</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">hasMany</span><span class="token punctuation">(</span><span class="token class-name static-context">Invoice</span><span class="token operator">::</span><span class="token function">className</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'_id'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'order_id'</span><span class="token punctuation">]</span><span class="token punctuation">)</span></span>
<span class="line">                    <span class="token operator">-></span><span class="token function">via</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'orders'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">limit</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>NOTE:</strong> Elasticsearch limits the number of records returned by any query to 10 records by default. This applies to queries executed when getting related models. If you expect to get more records you should specify the limit explicitly in relation definition. It is also important for [[yii\elasticsearch\ActiveQuery::via()|via]]-relations to set the proper limit both in the relation itself as well as the underlying relation that is used as an intermediary.</p>
</blockquote>
<h3 id="scalar-and-array-attributes" tabindex="-1"><a class="header-anchor" href="#scalar-and-array-attributes"><span>Scalar and array attributes</span></a></h3>
<p>Any field in an Elasticsearch document <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/array.html" target="_blank" rel="noopener noreferrer">can hold multiple values</a>. For example, if a customer mapping includes a keyword field for order ID, it is automatically possible to create a document with one, two, or more order IDs. One can say that every field in a document is an array.</p>
<p>For consistency with [[yii\base\ActiveRecord]], when populating the record from data, single-item arrays are replaced with the value they contain. However, it is possible to override this behavior by defining [[yii\elasticsearch\ActiveRecord::arrayAttributes()|arrayAttributes()]].</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">arrayAttributes</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'order_ids'</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>This way once fetched from the database, <code v-pre>$customer-&gt;order_ids</code> will be an array even if it contains one item, e.g. <code v-pre>['AB-32162']</code>.</p>
<h3 id="organizing-complex-queries" tabindex="-1"><a class="header-anchor" href="#organizing-complex-queries"><span>Organizing complex queries</span></a></h3>
<p>Any query can be composed using Elasticsearch’s query DSL and passed to the [[yii\elasticsearch\Query::query()|query()]] method. However, ES query DSL is notorious for its verbosity, and these oversized queries soon become unmanageable.</p>
<p>The usual approach with SQL ActiveRecord classes is to create scopes using methods in the query class that modify the query itself. This does not work so well with Elasticsearch, so the recommended approach is to create static methods that return building blocks of the query, then combine them.</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">CustomerQuery</span> <span class="token keyword">extends</span> <span class="token class-name">ActiveQuery</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">function</span> <span class="token function-definition function">name</span><span class="token punctuation">(</span><span class="token variable">$name</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'match'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'name'</span> <span class="token operator">=></span> <span class="token variable">$name</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">function</span> <span class="token function-definition function">address</span><span class="token punctuation">(</span><span class="token variable">$address</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'match'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'address'</span> <span class="token operator">=></span> <span class="token variable">$address</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">function</span> <span class="token function-definition function">registrationDateRange</span><span class="token punctuation">(</span><span class="token variable">$dateFrom</span><span class="token punctuation">,</span> <span class="token variable">$dateTo</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'range'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'registered_at'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token string single-quoted-string">'gte'</span> <span class="token operator">=></span> <span class="token variable">$dateFrom</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token string single-quoted-string">'lte'</span> <span class="token operator">=></span> <span class="token variable">$dateTo</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>Now these sub-queries can be used to build the query.</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$customers</span> <span class="token operator">=</span> <span class="token class-name static-context">Customer</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'bool'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'must'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token class-name static-context">CustomerQuery</span><span class="token operator">::</span><span class="token function">registrationDateRange</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'2016-01-01'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'2016-01-20'</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token string single-quoted-string">'should'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token class-name static-context">CustomerQuery</span><span class="token operator">::</span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'John'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token class-name static-context">CustomerQuery</span><span class="token operator">::</span><span class="token function">address</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'London'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token string single-quoted-string">'must_not'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token class-name static-context">CustomerQuery</span><span class="token operator">::</span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Jack'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">all</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="aggregations" tabindex="-1"><a class="header-anchor" href="#aggregations"><span>Aggregations</span></a></h3>
<p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations.html" target="_blank" rel="noopener noreferrer">The aggregations framework</a> helps provide aggregated data based on a search query. It is based on simple building blocks called aggregations, that can be composed in order to build complex summaries of the data.</p>
<p>As an example, let’s determine how many customers have been registered each month.</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$searchResult</span> <span class="token operator">=</span> <span class="token class-name static-context">Customer</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">addAggregate</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'customers_by_date'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'date_histogram'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'field'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'registered_at'</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token string single-quoted-string">'calendar_interval'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'month'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">limit</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">search</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$customersByDate</span> <span class="token operator">=</span> <span class="token class-name static-context">ArrayHelper</span><span class="token operator">::</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token variable">$searchResult</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'aggregations'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'customers_by_date'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'buckets'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'key_as_string'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'doc_count'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>Note that in this example [[yii\elasticsearch\ActiveQuery::search()|search()]] is used in place of [[yii\elasticsearch\ActiveQuery::one()|one()]] or [[yii\elasticsearch\ActiveQuery::all()|all()]]. The <code v-pre>search()</code> method returns not only the models, but also query metadata: shard statistics, aggregations, etc. When using aggregations, the search results (hits) themselves often don’t matter. That is why we’re using [[yii\elasticsearch\ActiveQuery::limit()|limit(0)]] to only return the metadata.</p>
<p>After some processing, <code v-pre>$customersByDate</code> contains data similar to this:</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'2020-01-01'</span> <span class="token operator">=></span> <span class="token number">5</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'2020-02-01'</span> <span class="token operator">=></span> <span class="token number">3</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'2020-03-01'</span> <span class="token operator">=></span> <span class="token number">17</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="suggesters" tabindex="-1"><a class="header-anchor" href="#suggesters"><span>Suggesters</span></a></h3>
<p>Sometimes it is necessary to suggest search terms that are similar to the search query and exist in the index. For example, it might be useful to find known alternative spellings of a name. See the example below, and also <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters.html" target="_blank" rel="noopener noreferrer">Elasticsearch docs</a> for details.</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$searchResult</span> <span class="token operator">=</span> <span class="token class-name static-context">Customer</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">limit</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span></span>
<span class="line"><span class="token operator">-></span><span class="token function">addSuggester</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'customer_name'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'text'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'Hans'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'term'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'field'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'name'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">search</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// Note that limit(0) will prevent the query from returning hits,</span></span>
<span class="line"><span class="token comment">// so only suggestions are returned</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$suggestions</span> <span class="token operator">=</span> <span class="token class-name static-context">ArrayHelper</span><span class="token operator">::</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token variable">$searchResult</span><span class="token punctuation">[</span><span class="token string double-quoted-string">"suggest"</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string double-quoted-string">"customer_name"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'text'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'options'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$names</span> <span class="token operator">=</span> <span class="token class-name static-context">ArrayHelper</span><span class="token operator">::</span><span class="token function">getColumn</span><span class="token punctuation">(</span><span class="token variable">$suggestions</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'Hans'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'text'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token comment">// $names == ['Hanns', 'Hannes', 'Hanse', 'Hansi']</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="unusual-behavior-of-attributes-with-object-mapping" tabindex="-1"><a class="header-anchor" href="#unusual-behavior-of-attributes-with-object-mapping"><span>Unusual behavior of attributes with object mapping</span></a></h3>
<p>The extension updates records using the <code v-pre>_update</code> endpoint. Since this endpoint is designed to perform partial updates to documents, all attributes that have an “object” mapping type in Elasticsearch will be merged with existing data. To demonstrate:</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$customer</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Customer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$customer</span><span class="token operator">-></span><span class="token property">my_attribute</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'foo'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'v1'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'bar'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'v2'</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$customer</span><span class="token operator">-></span><span class="token function">save</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token comment">// at this point the value of my_attribute in Elasticsearch is {"foo": "v1", "bar": "v2"}</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$customer</span><span class="token operator">-></span><span class="token property">my_attribute</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'foo'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'v3'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'bar'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'v4'</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$customer</span><span class="token operator">-></span><span class="token function">save</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token comment">// now the value of my_attribute in Elasticsearch is {"foo": "v3", "bar": "v4"}</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$customer</span><span class="token operator">-></span><span class="token property">my_attribute</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'baz'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'v5'</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$customer</span><span class="token operator">-></span><span class="token function">save</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token comment">// now the value of my_attribute in Elasticsearch is {"foo": "v3", "bar": "v4", "baz": "v5"}</span></span>
<span class="line"><span class="token comment">// but $customer->my_attribute is still equal to ['baz' => 'v5']</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>Since this logic only applies to objects, the solution is to wrap the object into a single-element array. Since to Elasticsearch a single-element array is the same thing as the element itself, there is no need to modify any other code.</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$customer</span><span class="token operator">-></span><span class="token property">my_attribute</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'new'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'value'</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">// note the double brackets</span></span>
<span class="line"><span class="token variable">$customer</span><span class="token operator">-></span><span class="token function">save</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token comment">// now the value of my_attribute in Elasticsearch is {"new": "value"}</span></span>
<span class="line"><span class="token variable">$customer</span><span class="token operator">-></span><span class="token property">my_attribute</span> <span class="token operator">=</span> <span class="token variable">$customer</span><span class="token operator">-></span><span class="token property">my_attribute</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">// could be done for consistency</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>For more information see this discussion: <a href="https://discuss.elastic.co/t/updating-an-object-field/110735" target="_blank" rel="noopener noreferrer">discuss.elastic.co/t/updating-an-o...</a></p>
<h2 id="working-with-data-providers" tabindex="-1"><a class="header-anchor" href="#working-with-data-providers"><span>Working with data providers</span></a></h2>
<p>The extension comes with its own enhanced and optimized [[\yii\elasticsearch\ActiveDataProvider|ActiveDataProvider]] class. The enhancements include:</p>
<ul>
<li>Total record count is obtained from the same query that gets the records themselves, not in a separate query.</li>
<li>Aggregation data is available as a property of the data provider.</li>
</ul>
<p>While [[\yii\elasticsearch\Query]] and [[\yii\elasticsearch\ActiveQuery]] can be used with [[\yii\data\ActiveDataProvider]], this is not recommended.</p>
<blockquote>
<p>NOTE: The data provider fetches result models and total count using single Elasticsearch query, so results total count will be fetched after pagination limit applying, which eliminates ability to verify if requested page number actually exist. The data provider disables [[yii\data\Pagination::$validatePage]] automatically because of this.</p>
</blockquote>
<h3 id="usage-examples-1" tabindex="-1"><a class="header-anchor" href="#usage-examples-1"><span>Usage examples</span></a></h3>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">yii<span class="token punctuation">\</span>elasticsearch<span class="token punctuation">\</span>ActiveDataProvider</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">yii<span class="token punctuation">\</span>elasticsearch<span class="token punctuation">\</span>Query</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// Using Query</span></span>
<span class="line"><span class="token variable">$query</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$query</span><span class="token operator">-></span><span class="token function">from</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'customer'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// ActiveQuery can also be used</span></span>
<span class="line"><span class="token comment">// $query = Customer::find();</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$query</span><span class="token operator">-></span><span class="token function">addAggregate</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'date_histogram'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'field'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'registered_at'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'calendar_interval'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'month'</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$query</span><span class="token operator">-></span><span class="token function">addSuggester</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'customer_name'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'text'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'Hans'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'term'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'field'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'customer_name'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$dataProvider</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ActiveDataProvider</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'query'</span> <span class="token operator">=></span> <span class="token variable">$query</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'pagination'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'pageSize'</span> <span class="token operator">=></span> <span class="token number">10</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$models</span> <span class="token operator">=</span> <span class="token variable">$dataProvider</span><span class="token operator">-></span><span class="token function">getModels</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$aggregations</span> <span class="token operator">=</span> <span class="token variable">$dataProvider</span><span class="token operator">-></span><span class="token function">getAggregations</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$suggestion</span> <span class="token operator">=</span> <span class="token variable">$dataProvider</span><span class="token operator">-></span><span class="token function">getSuggestions</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="using-the-elasticsearch-debugpanel" tabindex="-1"><a class="header-anchor" href="#using-the-elasticsearch-debugpanel"><span>Using the Elasticsearch DebugPanel</span></a></h2>
<p>The yii2 Elasticsearch extension provides a <code v-pre>DebugPanel</code> that can be integrated with the yii debug module and shows the executed Elasticsearch queries. It also allows to run these queries and view the results.</p>
<p>Add the following to you application config to enable it (if you already have the debug module enabled, it is sufficient to just add the panels configuration):</p>
<div class="language-text-html-php line-numbers-mode" data-highlighter="prismjs" data-ext="text-html-php" data-title="text-html-php"><pre v-pre class="language-text-html-php"><code><span class="line">    // ...</span>
<span class="line">    'bootstrap' =&gt; ['debug'],</span>
<span class="line">    'modules' =&gt; [</span>
<span class="line">        'debug' =&gt; [</span>
<span class="line">            'class' =&gt; 'yii\\debug\\Module',</span>
<span class="line">            'panels' =&gt; [</span>
<span class="line">                'elasticsearch' =&gt; [</span>
<span class="line">                    'class' =&gt; 'yii\\elasticsearch\\DebugPanel',</span>
<span class="line">                ],</span>
<span class="line">            ],</span>
<span class="line">        ],</span>
<span class="line">    ],</span>
<span class="line">    // ...</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="using-the-elasticsearch-debugpanel-1" tabindex="-1"><a class="header-anchor" href="#using-the-elasticsearch-debugpanel-1"><span>Using the Elasticsearch DebugPanel</span></a></h2>
<p>The yii2 Elasticsearch extension provides a <code v-pre>DebugPanel</code> that can be integrated with the yii debug module and shows the executed Elasticsearch queries. It also allows to run these queries and view the results.</p>
<p>Add the following to you application config to enable it (if you already have the debug module enabled, it is sufficient to just add the panels configuration):</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line">    <span class="token comment">// ...</span></span>
<span class="line">    <span class="token string single-quoted-string">'bootstrap'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'debug'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'modules'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'debug'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'yii\\debug\\Module'</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token string single-quoted-string">'panels'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">                <span class="token string single-quoted-string">'elasticsearch'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">                    <span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'yii\\elasticsearch\\DebugPanel'</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><img src="https://cdn.learnku.com/uploads/images/202202/14/93088/fx33DLHiP1.png!large" alt="Elasticsearch DebugPanel"></p>
<blockquote>
<p>💖喜欢本文档的，欢迎点赞、收藏、留言或转发，谢谢支持！<br>
作者邮箱：zhuzixian520@126.com，github地址：<a href="https://github.com/zhuzixian520" target="_blank" rel="noopener noreferrer">github.com/zhuzixian520</a></p>
</blockquote>
</div></template>


